/***************************************************
*	(c) Tody 2012, T-ware Inc.
*
*	Free software under GPLv3
*
*	Function: get DRM* widevine keybox data from MIS ShopFloor
*	FileName: miswvkey.c
*	Author: Tody Guo
*
* changelog:
*	v1.0.0 @ 2014-10-19
*	*) first release...
****************************************************/

#include "soapH.h"
#include "ServiceSoap.nsmap"

#define progname	"mis"
#define	version		"1.0.3"
#define DEBUG				1

typedef struct _wvbox
{
	char DeviceId[32];
	unsigned char Key[16];
	unsigned char ID[72];
	unsigned char Magic[4];
	unsigned char CRC[4];
}WVBOX;

typedef struct uniqData
{
	unsigned char SN[256];
	unsigned char UUID[256];
	unsigned char LANMAC[256];
	unsigned char WIFIMAC[256];
	unsigned char BTMAC[256];
	unsigned char OAKEY[256];
	unsigned char IMEI[256];
	unsigned char WVBOX[256];
	/* Add more mes data */
	unsigned char SITE[256];
	unsigned char WO[256];
	unsigned char BIOS[256];
	unsigned char CPUID[256];
	unsigned char SYSFLAG[256];
	unsigned char TDINDEX[256];
	unsigned char SHIPIMAGE[256];
	unsigned char WORKERID[256];
	unsigned char HDDSN[256];
}UNIQDATA;

void usage(void)
{
	fprintf(stderr, "Recieve MES data from Shopfloor tool   Version: %s\n"
					"\n(c) Tody 2014, T-ware Inc.\n"
					"\nUsage:\t%s -url http://172.20.160.1:888/Service.asmx [-g <Serialnumber> <customer-id>] [-c <File>] [-auto-station <File>]"
					"\nOptions:\n"
					"      -url <website>       website must be assigned\n"					
					"      -g                   get key from MES\n"
					"      customer-id          specified customer id to get keys\n"				
					"      Serialnumber         get Data from shopfloor via Tablet Serial number\n"
					"      Device ID            specified Device ID to shopfloor that was consumed\n"									
					"      -c File              specified formated file to check data with MES\n"
					"      -auto-station File   specified formated file to pass station to MES\n", version, progname );
	exit(1);
}

int getValueFromIni(char *inifile, UNIQDATA *data)
{
	GetPrivateProfileString("MESDATA", "SN", "NA", data->SN, 			256, inifile);
	GetPrivateProfileString("MESDATA", "UUID", "NA", data->UUID, 		256, inifile);
	GetPrivateProfileString("MESDATA", "LANMAC", "NA", data->LANMAC, 	256, inifile);
	GetPrivateProfileString("MESDATA", "WIFIMAC", "NA", data->WIFIMAC, 	256, inifile);
	GetPrivateProfileString("MESDATA", "BTMAC", "NA", data->BTMAC, 		256, inifile);
	GetPrivateProfileString("MESDATA", "OAKEY", "NA", data->OAKEY, 		256, inifile);
	GetPrivateProfileString("MESDATA", "IMEI", "NA", data->IMEI, 		256, inifile);
	GetPrivateProfileString("MESDATA", "WVBOX", "NA", data->WVBOX, 		256, inifile);
	GetPrivateProfileString("MESDATA", "SITE", "NA", data->SITE, 		256, inifile);
	GetPrivateProfileString("MESDATA", "WO", "NA", data->WO, 			256, inifile);
	GetPrivateProfileString("MESDATA", "BIOS", "NA", data->BIOS, 		256, inifile);
	GetPrivateProfileString("MESDATA", "CPUID", "NA", data->CPUID, 		256, inifile);
	GetPrivateProfileString("MESDATA", "SYSFLAG", "NA", data->SYSFLAG, 	256, inifile);
	GetPrivateProfileString("MESDATA", "TDINDEX", "NA", data->TDINDEX, 	256, inifile);
	GetPrivateProfileString("MESDATA", "SHIPIMAGE", "NA", data->SHIPIMAGE, 	256, inifile);
	GetPrivateProfileString("MESDATA", "WORKERID", "NA", data->WORKERID, 	256, inifile);
	GetPrivateProfileString("MESDATA", "HDDSN", "NA", data->HDDSN, 	256, inifile);	
}

int charToHex(char ch)
{
	switch(ch){
		case '0':	return 0; break;
		case '1':	return 1; break;
		case '2':	return 2; break;
		case '3':	return 3; break;
		case '4':	return 4; break;
		case '5':	return 5; break;
		case '6':	return 6; break;
		case '7':	return 7; break;
		case '8':	return 8; break;
		case '9':	return 9; break;
		case 'a':	
		case 'A': return 10; break;
		case 'b':	
		case 'B':	return 11; break;
		case 'c':	
		case 'C':	return 12; break;
		case 'd':	
		case 'D':	return 13; break;
		case 'e':	
		case 'E':	return 14; break;
		case 'f':	
		case 'F':	return 15; break;
		default:
			printf("char error\n");
			exit(1);
	}
}

int dumpToBin(char *filename, WVBOX *wvbox)
{
	FILE *f;
	f = fopen(filename, "wb");
	fwrite(wvbox, sizeof(WVBOX), 1, f);
	fflush(f);
	fclose(f);	
} 

int doDataSplit(char *data, char *serialNumber)
{
	char *father;
	char buf[1024];
	WVBOX wvbox;
	int i=0, j=0;
	int index = 1;
	char filename[128];
	
	/* generate filename of BIN. according serial number */
	sprintf(filename, "%s.BIN", serialNumber);
	
	memset(buf,0,sizeof(buf));
	memset(&wvbox,0,sizeof(WVBOX));

	strcpy(buf, data);
	
	printf("\nDecode MES Data...");	
	father= strtok(buf, "|");
	while (father!=NULL)
	{
		switch(index){
			case 1: /* DeviceID */
				strcpy(wvbox.DeviceId, father);
				printf("\nDevice ID:%s", wvbox.DeviceId);
				break;
			case 2: /* Key */
				printf("\nKey: %s", father);
				if(strlen(father)!=32){
					printf("\n[-] Key length error");
					exit(1);
				}
				for(i=0, j=0; i<32; i=i+2){
					wvbox.Key[j] = charToHex(father[i])*16+charToHex(father[i+1]);
					j++; 
				}
				break;
			case 3:/* ID */
				printf("\nID: %s", father);
				if(strlen(father)!=144){
					printf("\n[-] ID length error");
					exit(1);
				}
				for(i=0, j=0; i<144; i=i+2){
					wvbox.ID[j] = charToHex(father[i])*16+charToHex(father[i+1]);
					j++; 
				}
				break;
			case 4:/* Magic */
				printf("\nMagic: %s", father);
				if(strlen(father)!=8){
					printf("\n[-] Magic length error");
					exit(1);
				}
				for(i=0, j=0; i<8; i=i+2){
					wvbox.Magic[j] = charToHex(father[i])*16+charToHex(father[i+1]);
					j++; 
				}
				break;
			case 5: /* CRC */
				printf("\nCRC: %s", father);
				if(strlen(father)!=8){
					printf("\n[-] CRC length error");
					exit(1);
				}
				for(i=0, j=0; i<8; i=i+2){
					wvbox.CRC[j] = charToHex(father[i])*16+charToHex(father[i+1]);
					j++; 
				}
				break;
		}
		father = strtok(NULL, "|");
		index++;
	}
	
	if((index-1)!=5){
		printf("\n[-]Keybox format error!");
		exit(1);
	}
	
	dumpToBin(filename, &wvbox);
}


int main(int argc, char *argv[])
{
	struct soap 					*soap;
	struct _ns1__FetchKeystr 		sn;
	struct _ns1__FetchKeystrResponse 	retData;
	
	struct _ns1__Check_USCOREUnique uniq;
	struct _ns1__Check_USCOREUniqueResponse uniqRes;
	UNIQDATA uData;
	
	struct _ns1__SN_USCOREAutoProcess autoProc;
	struct _ns1__SN_USCOREAutoProcessResponse autoProcRes;
	
	char MISDATA[512];   /*Size is ok for later use?*/
	char *website;

	memset(MISDATA, 0, sizeof(MISDATA));
	
	if (argc >= 3 && strcmp("-url" ,argv[1])!=0)
	{
		usage();
	}else if (argc >= 3 && strstr(argv[2], "http://") != NULL)
	{
		website = argv[2];
	}else{
		/*using default website.*/
		website = NULL;
	}

	printf("Accessing %s...\n", website==NULL? "Default website":website);

	soap = soap_new();

	if ( argc == 6 && strcmp("-g", argv[3])==0 )
	{
		sn.sn = argv[4];
		sn.customer = argv[5];
		retData.FetchKeystrResult = MISDATA;

		if (soap_call___ns1__FetchKeystr(soap, website, NULL, &sn, &retData) == SOAP_OK)
		{
			if (strlen(retData.FetchKeystrResult) != 0)
			{
				fprintf(stdout, "\n-------------------------------------------------------------------------------"); 
				fprintf(stdout, "\nMIS: %s", retData.FetchKeystrResult); 
				fprintf(stdout, "\n-------------------------------------------------------------------------------");
				doDataSplit(retData.FetchKeystrResult, argv[4]);
				fflush(stdout);
			}else{
				soap_end(soap);
				free(soap);
				printf(" -> data not found!");
				exit(1);
			}
		}
		else
		{
			soap_end(soap);
			free(soap);
			fprintf(stdout, "[-] network issue!");
			exit(1);
		}
	} 
	else if ( argc == 5 && strcmp("-c", argv[3])==0 )
	{
		memset(&uData, 0, sizeof(UNIQDATA));

		getValueFromIni(argv[4], &uData);
		
		uniq.TSN = uData.SN;
		uniq.TUUID = uData.UUID;
		uniq.TLANMAC = uData.LANMAC;
		uniq.TWIFIMAC = uData.WIFIMAC;
		uniq.TBTMAC = uData.BTMAC;
		uniq.TOAKEY = uData.OAKEY;
		uniq.TIMEI = uData.IMEI;
		uniq.TWVBOX = uData.WVBOX;
		uniq.THDD = uData.HDDSN;
		uniq.TERIMINALID = uData.SITE;
		
		printf("\nCheck-process...\nTSN: %s\nTUUID: %s\nTLANMAC: %s\nTWIFIMAC: %s\nTBTMAC: %s\nTOAKEY: %s\nTIMEI: %s\nTWVBOX: %s\nTHDD: %s\n",
				 uniq.TSN, uniq.TUUID, uniq.TLANMAC, uniq.TWIFIMAC , uniq.TBTMAC , uniq.TOAKEY , uniq.TIMEI , uniq.TWVBOX, uniq.THDD);	
		
		if (soap_call___ns1__Check_USCOREUnique(soap, website, NULL, &uniq, &uniqRes) == SOAP_OK){
			fprintf(stdout, "\nMES:%s", uniqRes.Check_USCOREUniqueResult);
			fflush(stdout);
		}
		else
		{
			fprintf(stdout, "[-] network issue!");
			soap_end(soap);
			free(soap);
			exit(1);
		}

	}else if ( argc == 5 && strcmp("-auto-station", argv[3])==0 )
	{
		memset(&uData, 0, sizeof(UNIQDATA));

		getValueFromIni(argv[4], &uData);
		
		autoProc.TSN = uData.SN;
		autoProc.TUUID = uData.UUID;
		autoProc.TLANMAC = uData.LANMAC;
		autoProc.TWIFIMAC = uData.WIFIMAC;
		autoProc.TBTMAC = uData.BTMAC;
		autoProc.TOAKEY = uData.OAKEY;
		autoProc.TIMEI = uData.IMEI;
		autoProc.TWVBOX = uData.WVBOX;
		autoProc.TSITEY = uData.SITE;
		autoProc.TWO = uData.WO;
		autoProc.TBIOS = uData.BIOS;
		autoProc.TCPUID = uData.CPUID;
		autoProc.TSYSFLAG = uData.SYSFLAG;
		autoProc.TDINDEX = uData.TDINDEX;
		autoProc.TSHIPIMAGE = uData.SHIPIMAGE;
		autoProc.TEMP = uData.WORKERID;

		printf("\nAuto-process...\nTSN: %s\nTUUID: %s\nTLANMAC: %s\nTWIFIMAC: %s\nTBTMAC: %s\nTOAKEY: %s\nTIMEI: %s\nTWVBOX: %s\n",
				 autoProc.TSN, autoProc.TUUID, autoProc.TLANMAC, autoProc.TWIFIMAC , autoProc.TBTMAC , autoProc.TOAKEY , autoProc.TIMEI , autoProc.TWVBOX );	
		if (soap_call___ns1__SN_USCOREAutoProcess_(soap, website, NULL, &autoProc, &autoProcRes) == SOAP_OK){
			fprintf(stdout, "\nMES:%s", autoProcRes.SN_USCOREAutoProcessResult);
			fflush(stdout);
		}
		else
		{
			fprintf(stdout, "[-] network issue!");
			soap_end(soap);
			free(soap);
			exit(1);
		}
	}else{
		usage();
	}

	soap_end(soap);
	free(soap);
	
	exit(0);  /*normal exit from program*/
}

